正如前几节所述，声明依赖于模板参数类型有不同的方式:

\begin{itemize}
\item 
通过值传递参数:

这种方法很简单，衰变字符串字面值和数组，但不能为大型对象提供最佳性能。调用者可以决定使用std::cref()和std::ref()通过引用传递，但是必须确定这样做的必要性。

\item 
通过引用传递参数:

这种方法通常可以为大型对象提供更好的性能，特别是在传递参数时

\begin{itemize}
\item[-]
现有对象(lvalue)到左值引用，

\item[-]
临时对象(prvalue)或标记为可移动(xvalue)的对象将引用右值，

\item[-]
或者两者都为转发引用。
\end{itemize}

这些情况下，参数都不会衰变，所以在传递字符串字面值和其他数组时，可能需要特别注意。对于转发引用，还必须注意使用模板参数隐式推导出引用类型的方法。
\end{itemize}

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{不要过于泛化}

实践中，函数模板通常不支持任意类型的参数，可以进行了一些约束。例如，可能知道只传递某种类型的vector。这种情况下，最好不要太泛化地声明这样的函数。如前所述，这可能会出现令人惊讶的副作用，可以使用以下声明:

\begin{lstlisting}[style=styleCXX]
template<typename T>
void printVector (std::vector<T> const& v)
{
	...
}
\end{lstlisting}

通过在printVector()中声明参数v，可以确定传递的T不能成为引用，因为vector不能使用引用作为元素类型。另外，因为std::vector<>的复制构造函数会创建元素副本，所以按值传递vector的成本很高。出于这个原因，将这样的vector参数声明为按值传递可能不合适。若将参数v的声明交由类型T来决定，那么按值调用和按引用调用之间的区别就不那么明显了。

\hspace*{\fill} \\ %插入空行
\noindent
\textbf{std::make\_pair()的实例}

std::make\_pair<>()是一个很好的例子，演示了决定参数传递机制的缺陷。C++标准库中，可以使用其进行类型推导，并创建std::pair<>对象(一个方便的函数模板)。它的声明在不同版本的C++标准中有所不同:

\begin{itemize}
\item
C++98中，make\_pair<>()在命名空间std中声明，使用引用调用来避免不必要的复制:

\begin{lstlisting}[style=styleCXX]
template<typename T1, typename T2>
pair<T1,T2> make_pair (T1 const& a, T2 const& b)
{
	return pair<T1,T2>(a,b);
}
\end{lstlisting}

然而，使用字符串字面值对或不同大小的数组时，这会导致严重的问题。

\begin{tcolorbox}[colback=webgreen!5!white,colframe=webgreen!75!black]
\hspace*{0.75cm}请参见C++库的181号issue[LibIssue181]
\end{tcolorbox}

\item
C++03中，函数定义改为使用按值调用:

\begin{lstlisting}[style=styleCXX]
template<typename T1, typename T2>
pair<T1,T2> make_pair (T1 a, T2 b)
{
	return pair<T1,T2>(a,b);
}
\end{lstlisting}

如同在问题解决方案的基本原理中所了解到的那样，“与其他两个建议相比，这似乎是对标准的一个小修改，而且任何效率方面的担忧都由该解决方案的优点所抵消。”

\item[-]
C++11中，make\_pair()必须支持移动语义，因此参数必须成为转发引用。因此，该定义又发生了如下变化:

\begin{lstlisting}[style=styleCXX]
template<typename T1, typename T2>
constexpr pair<typename decay<T1>::type, typename decay<T2>::type>
make_pair (T1&& a, T2&& b)
{
	return pair<typename decay<T1>::type,
				typename decay<T2>::type>(forward<T1>(a),
										  forward<T2>(b));
}
\end{lstlisting}

完整的实现甚至更加复杂:为了支持std::ref()和std::cref()，该函数还将std::reference\_wrapper的实例展开为实际的引用。
\end{itemize}

C++标准库现在在许多地方以类似的方式完美地转发传递的参数，并与std::decay<>一起使用。


















